/*
----------------------------------------------------------------------------------------------------
This source file is part of the Gamut Framework
Copyright (c) 2007 by Ryan Holcombe

This program is free software; you can redistribute it and/or modify it under the terms of the GNU
Lesser General Public License as published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
----------------------------------------------------------------------------------------------------
*/

#include "GamutManagerFactory.h"
#include "GamutIManager.h"
#include "GamutLogger.h"
#include "GamutException.h"
#include "GamutStateManager.h"
#include "GamutGameObjectManager.h"
#include <limits>

namespace Gamut
{
	//! Declare Singleton
	template<> ManagerFactory* Singleton<ManagerFactory>::ms_Singleton = 0;

	// -------------------------------------------------------------------------------------------//
	ManagerFactory::ManagerFactory()
	{
		LOGF4("Singleton ManagerFactory (%p) created", this);

		registerManager(IManagerPtr(new StateManager("StateManager", 20)));
		registerManager(IManagerPtr(new GameObjectManager("GOManager", 10)));

		registerCustomManagers();
	}
	
	// -------------------------------------------------------------------------------------------//
	ManagerFactory::~ManagerFactory()
	{
		// empty out the active list
		while (mActiveList.size() > 0)
			removeManager(*mActiveList.begin());

		// unregister all the managers based on priority
		RegisteredMap::iterator iterDestroy;
		unsigned int priority;

		while (mRegisteredMap.size() > 0) {
			priority = std::numeric_limits<unsigned int>::max();

			// find the map with the lowest priority
			for (RegisteredMap::iterator iter = mRegisteredMap.begin(); iter != mRegisteredMap.end(); ++iter)
			{
				if (iter->second->getPriority() <= priority)
					iterDestroy = iter;
			}
			unregisterManager(iterDestroy->first);
		}

		while (mRegisteredMap.size() > 0)
			unregisterManager(mRegisteredMap.begin()->first);
		
		LOGF4("Singleton ManagerFactory (%p) destroyed", this);
	}
	
	// -------------------------------------------------------------------------------------------//
	IManagerPtr ManagerFactory::registerManager(IManagerPtr manager)
	{
		// verify that all necessary variables have been set by the class
		if (manager->getName() == "")
			throw Exception("ManagerFactory::registerManager", "Unable to register Manager [" +
							manager->getName() + "], mName must be set by the class");

		if (manager->getPriority() == 0)
			throw Exception("ManagerFactory::registerManager", "Unable to register Manager [" +
							manager->getName() + "], mPriority must be > 0");

		// verify the manager does not already exist in the map
		RegisteredMap::iterator iter = mRegisteredMap.find(manager->getName());
		if (iter != mRegisteredMap.end())
		{
			LOG2("Unable to register Manager [" + manager->getName() + "], it already exists");
			return (iter->second);
		}
		
		mRegisteredMap.insert(std::make_pair<const std::string, IManagerPtr>(manager->getName(), manager));
		
		LOG4("Manager [" + manager->getName() + "] registered");
		return (manager);
	}
	
	// -------------------------------------------------------------------------------------------//
	void ManagerFactory::unregisterManager(const std::string& name)
	{
		// remove from active manager list if it's there
		if (std::find(mActiveList.begin(), mActiveList.end(), name) != mActiveList.end())
			removeManager(name);

		RegisteredMap::iterator iter = mRegisteredMap.find(name);
		if (iter == mRegisteredMap.end())
		{
			LOG2("Unable to unregister Manager [" + name + "], it was not found in the map");
			return;
		}
		
		LOG4("Manager [" + iter->first + "] unregistered");
		mRegisteredMap.erase(iter);
	}
	
	// -------------------------------------------------------------------------------------------//
	IManagerPtr ManagerFactory::addManager(const std::string& name)
	{
		RegisteredMap::iterator iter = mRegisteredMap.find(name);
		if (iter == mRegisteredMap.end())
			throw Exception("ManagerFactory::addManager", "Unable to add Manager [" + name +
							"], it has not been registered");

		if (std::find(mActiveList.begin(), mActiveList.end(), name) != mActiveList.end())
		{
			LOG2("Unable to create Manager [" + name + "], it already exists");
			return (iter->second);
		}
		
		LOG3("Manager [" + name + "] added");

		// insert the object in priority order, higher priorities will be run last
		ActiveList::iterator insert = mActiveList.end();
		unsigned int priority = iter->second->getPriority();
		unsigned int insertPriority = std::numeric_limits<unsigned int>::max();
		for (ActiveList::iterator it = mActiveList.begin(); it != mActiveList.end(); ++it)
		{
			unsigned int itPriority = mRegisteredMap[*it]->getPriority();
			if (itPriority > priority && itPriority < insertPriority)
			{
				insertPriority = itPriority;
				insert = it;
			}

		}
		mActiveList.insert(insert, name);
		
		return (iter->second);
	}

	// -------------------------------------------------------------------------------------------//
	void ManagerFactory::removeManager(const std::string& name)
	{
		ActiveList::iterator iter = std::find(mActiveList.begin(), mActiveList.end(), name);
		if (iter == mActiveList.end())
		{
			LOG2("Unable to remove Manager [" + name + "], it was not found in the active list");
			return;
		}

		LOG3("Manager [" + name + "] removed");

		mActiveList.erase(iter);
	}

	// -------------------------------------------------------------------------------------------//
	IManagerPtr ManagerFactory::getManager(const std::string& name) const
	{
		// Check to see if the manager is active
		if (std::find(mActiveList.begin(), mActiveList.end(), name) == mActiveList.end())
			LOG2("Trying to get an unactive manager, [" + name + "]");
			
		RegisteredMap::const_iterator iter = mRegisteredMap.find(name);

		if (iter == mRegisteredMap.end())
			throw Exception("ManagerFactory::getManager", "Manager [" + name + "] has not been registered");

		return (iter->second);
	}

	// -------------------------------------------------------------------------------------------//
	bool ManagerFactory::isManagerActive(const std::string& name) const
	{
		if (std::find(mActiveList.begin(), mActiveList.end(), name) == mActiveList.end())
			return (0);

		return (1);
	}

	// -------------------------------------------------------------------------------------------//
	void ManagerFactory::tick(double elapsed)
	{
		ActiveList::iterator activeIter;
		for (activeIter = mActiveList.begin(); activeIter != mActiveList.end(); ++activeIter)
		{
			const std::string& name = *activeIter;

			// verify that the active state exists in the registered map
			RegisteredMap::iterator registeredIter = mRegisteredMap.find(name);
			if (registeredIter == mRegisteredMap.end())
				throw Exception("ManagerFactory::tick", "Unable to find active state [" + name +
								"] in the registration map");

			registeredIter->second->tick(elapsed);
		}
	}
}
